#include <sys/stat.h>
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>
#include <unistd.h>
#include <vector>
#include <queue>
#include <signal.h>
#include <sys/types.h>
#include <stdio.h>
using namespace::std;
#include "ProcessData.h"

//=======================================================================//
//======================   functions declarations  ======================//
//=======================================================================//

void askForSetupFile(ifstream* input);
void readSetupFile(ifstream* fileName,vector<ProcessData*>* procInfo);
int askForSchedulingPolicy();
int askForCpuTimeQuantom();
int askUserForInstructions();
void roundRobinSched();
void clockTick(int dummy);
void blockingRequest(int dummy);
char* intToChar(int num);

void runProcess(ProcessData* info);
void User1_handler(int num);
void User2_handler(int num);


//=======================================================================//
//======================   variables declarations  ======================//
//=======================================================================//

pid_t schedpid;
int numberOfProcesses;
int numberOfLiveProcesses;
int currentProcessIndex;
int timeQuantom;
int totalRunningTime;
int currentRunningTime;
vector<ProcessData*>* procInfo;
queue<ProcessData*>* readyQueue;
ProcessData* currentProcess;

//======================================================================//
//======================   main (also scheduler)  ======================//
//======================================================================//

int main()
{
    schedpid = getpid();
	ifstream input;
	int schedPolicy = 1;
	int userInstruction = 1;
	pid_t pid;
	procInfo = new vector<ProcessData*>;
	readyQueue = new queue<ProcessData*>;

	while (userInstruction != 5){
        if (userInstruction < 3){
            askForSetupFile(&input);
            readSetupFile(&input,procInfo);
        }
        /*if (userInstruction < 4)
            schedPolicy = 1;//askForSchedulingPolicy();
        if (userInstruction < 5)
            cpuTimeQuantom = 10;//askForCpuTimeQuantom();*/

        int size = procInfo->size();
        for (int i=0; i<size; i++){
            procInfo->at(i)->schedpid = schedpid;
            readyQueue->push(procInfo->at(i));
            cout << "creating process number " << i << endl;
            //const char name[]= "/users/studs/bsc/2007/amsalemg/workspace/Process/Debug/process";
            pid = fork();
            //char* args[13];
            //args[0] = "process";
            //args[12] = NULL;

            if (pid == 0){
            	//child process
            	runProcess(procInfo->at(i));
            }

            else{
            	procInfo->at(i)->mypid = pid;
            } //nothing yet
        }

        size = procInfo->size();
        for (int i=0; i<size; i++)
            cout << "process number " << i << " pid is " << procInfo->at(i)->mypid << endl;
        roundRobinSched();
        userInstruction = 5;
	}
    return 0;
}

/*
userInstruction = 5;
while (userInstruction == 1)
userInstruction = askUserForInstructions();*/

//============================================================//
//======================   round robin  ======================//
//============================================================//

void roundRobinSched(){
	signal(SIGUSR1,clockTick);
    signal(SIGUSR2,blockingRequest);
    numberOfLiveProcesses = numberOfProcesses;
	timeQuantom = 2;
	totalRunningTime = 0;
	currentRunningTime = 0;
	currentProcess = readyQueue->front();
	readyQueue->pop();
	currentProcessIndex = currentProcess->processIndex;

	while (!readyQueue->empty()){

		cout << "sendind sigusr1 to pid : " << currentProcess->mypid << endl;
		kill(currentProcess->mypid,SIGUSR1);
		pause();
	}
}

void clockTick(int dummy){
	//cout << "clock tick" << endl;
	signal(SIGUSR1,clockTick);
	sleep(1);

    currentRunningTime++;
    currentProcess->runningTime++;
    cout << "running for " << currentRunningTime << " seconds" << endl;

    if (currentProcess->runningTime >= currentProcess->totalTimeLimit){
    	cout << "process ended total time" << endl;
    	kill(currentProcess->mypid,SIGKILL);
    	currentRunningTime = 0;
    	currentProcess = readyQueue->front();
		readyQueue->pop();
		currentProcessIndex = currentProcess->processIndex;
    }
    else if (currentRunningTime >= timeQuantom){
    	cout << "process ended quantom time" << endl;
        kill(currentProcess->mypid,SIGUSR2);
        readyQueue->push(currentProcess);
        currentRunningTime = 0;
        currentProcess = readyQueue->front();
		readyQueue->pop();
		currentProcessIndex = currentProcess->processIndex;
    }
    else
    {
    	kill(currentProcess->mypid,SIGUSR1);
    }
}

void blockingRequest(int dummy){
	//cout << "blocking request" << endl;
	signal(SIGUSR2,blockingRequest);
	sleep(1);

	//something
}

//========================================================//
//======================   process  ======================//
//========================================================//

void runProcess(ProcessData* info){

	/*mypid = atoi(argv[10]);
	cout << "created new process, pid = " << mypid << "and vals:" << endl;

	totalTimeLimit = atoi(argv[1]);
	cout << "totalTimeLimit = " << totalTimeLimit << endl;
	initialPriority = atoi(argv[2]);
	cout << "initialPriority = " << initialPriority << endl;
	c1 = atoi(argv[3]);
	cout << "c1 = " << c1 << endl;
	c2 = atoi(argv[4]);
	cout << "c2 = " << c2 << endl;
	b1 = atoi(argv[5]);
	cout << "b1 = " << b1 << endl;
	b2 = atoi(argv[6]);
	cout << "b2 = " << b2 << endl;
	x0 = atoi(argv[7]);
	cout << "x0 = " << x0 << endl;
	y0 = atoi(argv[8]);
	cout << "y0 = " << y0 << endl;
	w = atoi(argv[9]);
	cout << "w = " << w << endl;
	schedpid = atoi(argv[11]);
	cout << "schedpid = " << schedpid << endl;
	curTime = 0;
	isBlocked = false;
	isReady = true;*/

	signal(SIGUSR1,User1_handler);
	signal(SIGUSR2,User2_handler);


	while (true){
		pause();
	}
}

void User1_handler(int num){
	/*if (isReady) {
		// the process was in the ready queue, new TQ is started
		int gap = c2 - c1;
		int iSecret = rand() % gap + 1;
		curTime = iSecret + c1;
		isReady = false;
	}

	curTime--; //time left in the current session
	*/
	// DEBUG
	//cout << "process #" << getpid() <<" going to sleep... zzz... zzz... zzz..." << endl;
	sleep(1);
	cout << "process #" << getpid() <<" running :)" << endl;
	// end DEBUG

	//if (curTime == 0) {
		// the process finish the current job
	//}

	kill(schedpid,SIGUSR1); //sending clock-tick to the scheduler
	//pause;
}

void User2_handler(int num){
	//kill(getpid(),SIGKILL);
}


//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//
//-----------------------------------------------------------------------//

char* intToChar(int num){
	string str = "" + num;
   	char* chr;
	strcpy(chr,str.c_str());
	return chr;
}


void askForSetupFile(ifstream* input){
    string path;
    while (true){
        cout << "Please enter setup file path:" << endl;
        //cin >> path;
        path = "conf_file.txt";
        input->open(path.c_str(), ios::in);
        if (input->is_open())
            return;
        else
            cout << "Can't open file" << endl;
    }
}

void readSetupFile(ifstream* inputFile,vector<ProcessData*>* procInfo){
    string line;
    getline(*inputFile,line);
    numberOfProcesses = atoi(line.c_str());
    ProcessData* p;
    string token;
    for (int m=0; m<numberOfProcesses; m++) {
        getline(*inputFile,line);
        p = new ProcessData(line,m);
        procInfo->push_back(p);
    }
    return;
}

int askForSchedulingPolicy(){
    string str;
    int i;
    while (true){
        cout << "Select your scheduling policy:" << endl;
        cout << "Enter 1 for \"Round Robin\"" << endl;
        cout << "Enter 2 for \"Guaranteed Scheduling\"" << endl;
        cout << "Enter 3 for \"Dynamic Multi Level Scheduling\"" << endl;
        cout << "Enter 4 for \"Mega Scheduling\"" << endl;
        cout << "Please enter your choice:" << endl;
        cin >> str;
        i = atoi(str.c_str());
        if ((i >= 1) && (i <= 4))
            return i;
        else
            cout << "Invalid input!" << endl;
    }
    return 0;
}

int askForCpuTimeQuantom(){
    string str;
    int i;
    while (true){
        cout << "Inser CPU time quantom (in miliseconds):" << endl;
        cin >> str;
        i = atoi(str.c_str());
        if (i > 0)
            return i;
        else
            cout << "Invalid input!" << endl;
    }
    return 0;
}

int askUserForInstructions(){
    string str;
    int i;
    while (true){
        cout << "What to do next?" << endl;
        cout << "Enter 1 for viewing statistics" << endl;
        cout << "Enter 2 for start with new setup file" << endl;
        cout << "Enter 3 for start with new policy" << endl;
        cout << "Enter 4 for start with new quantom" << endl;
        cout << "Enter 5 to exit" << endl;
        cout << "Please enter your choice:" << endl;
        cin >> str;
        i = atoi(str.c_str());
        if ((i >= 1) && (i <= 5))
            return i;
        else
            cout << "Invalid input!" << endl;;
    }
    return 0;
}

//cout << "args = " << procInfo->at(i)->mypid << endl;
            	//cout << "debug" << procInfo->at(i)->totalTimeLimit << endl;


            	/*
            	args[1] = intToChar(procInfo->at(i)->totalTimeLimit);
            	args[2] = intToChar(procInfo->at(i)->initialPriority);
            	args[3] = intToChar(procInfo->at(i)->c1);
            	args[4] = intToChar(procInfo->at(i)->c2);
            	args[5] = intToChar(procInfo->at(i)->b1);
            	args[6] = intToChar(procInfo->at(i)->b2);
            	args[7] = intToChar(procInfo->at(i)->x0);
            	args[8] = intToChar(procInfo->at(i)->y0);
            	args[9] = intToChar(procInfo->at(i)->w);
            	args[10] = intToChar(getpid());
            	args[11] = intToChar(schedpid);

                execvp(name,args);
                cout << "balagan" << endl;
                fprintf(stderr,"error");*/

